﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Flurl.Http;

namespace Pay.Core.AlipayWap {
	public class AlipayRefund {
		public AlipayRefund() {
		}

		private Dictionary<string, string> PayInfo = new Dictionary<string, string>();

		/// <summary>
		/// 退款
		/// </summary>
		/// <returns>The refund.</returns>
		/// <param name="payment_query">Payment query.</param>
		/// <param name="out_trade_no">Out trade no.</param>
		/// <param name="out_request_no">Out request no.</param>
		/// <param name="refund_amount">Refund amount.</param>
		public async Task<refund_response> GetRefund(payment_query payment_query, string out_trade_no,
											string out_request_no, decimal refund_amount) {
			string orderInfo = GetOrderInfoWithOutEncode(payment_query.app_id, out_trade_no, out_request_no, refund_amount);
			// 对订单做RSA 签名
			string sign = RSAFromPkcs8.sign(orderInfo, payment_query.app_secret, "utf-8");
			//仅需对sign做URL编码
			sign = HttpUtility.UrlEncode(sign, Encoding.UTF8);
			string url = "https://openapi.alipay.com/gateway.do?" + GetOrderInfoWithEncode() + "&sign=" + sign;
			var result = await url.GetAsync().ReceiveJson<alipay_refund_result>();
			return result.alipay_trade_refund_response;
		}

		/// <summary>
		/// 不包含Encode的字符串拼接
		/// </summary>
		/// <returns></returns>
		private string GetOrderInfoWithOutEncode(string app_id, string out_trade_no, string out_request_no, decimal refund_amount) {
			PayInfo.Add("app_id", app_id);
			PayInfo.Add("biz_content", GetBizContent(out_trade_no, out_request_no, refund_amount));
			PayInfo.Add("charset", "utf-8");
			PayInfo.Add("format", "json");
			PayInfo.Add("method", "alipay.trade.refund");
			PayInfo.Add("sign_type", "RSA");
			PayInfo.Add("timestamp", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
			PayInfo.Add("version", "1.0");
			string strUrl = BuildQueryWithOutEncode(PayInfo);
			return strUrl;
		}
		/// <summary>
		/// 包含Encode的字符串拼接
		/// </summary>
		/// <returns></returns>
		private string GetOrderInfoWithEncode() {
			string strUrl = BuildQuery(PayInfo, "utf-8");
			return strUrl;
		}

		private string GetBizContent(string out_trade_no, string out_request_no, decimal refund_amount) {
			Dictionary<string, object> biz_content_info = new Dictionary<string, object>();
			biz_content_info.Add("out_trade_no", out_trade_no);
			biz_content_info.Add("refund_amount", refund_amount);
			biz_content_info.Add("refund_reason", "正常退款");
			biz_content_info.Add("out_request_no", out_request_no);
			string strBizContent = biz_content_info.ToJson();
			return strBizContent;
		}


		/// <summary>
		/// 组装普通文本请求参数(带Encode)。
		/// </summary>
		/// <param name="parameters">Key-Value形式请求参数字典</param>
		/// <returns>URL编码后的请求数据</returns>
		private string BuildQuery(IDictionary<string, string> parameters, string charset) {
			StringBuilder postData = new StringBuilder();
			bool hasParam = false;

			IEnumerator<KeyValuePair<string, string>> dem = parameters.GetEnumerator();
			while (dem.MoveNext()) {
				string name = dem.Current.Key;
				string value = dem.Current.Value;
				// 忽略参数名或参数值为空的参数
				if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(value)) {
					if (hasParam) {
						postData.Append("&");
					}

					postData.Append(name);
					postData.Append("=");

					string encodedValue = HttpUtility.UrlEncode(value, Encoding.GetEncoding(charset));

					postData.Append(encodedValue);
					hasParam = true;
				}
			}
			return postData.ToString();
		}
		/// <summary>
		/// 组装普通文本请求参数(不带Encode)。
		/// </summary>
		/// <param name="parameters">Key-Value形式请求参数字典</param>
		/// <returns>URL编码后的请求数据</returns>
		private string BuildQueryWithOutEncode(IDictionary<string, string> parameters) {
			StringBuilder postData = new StringBuilder();
			bool hasParam = false;

			IEnumerator<KeyValuePair<string, string>> dem = parameters.GetEnumerator();
			while (dem.MoveNext()) {
				string name = dem.Current.Key;
				string value = dem.Current.Value;
				// 忽略参数名或参数值为空的参数
				if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(value)) {
					if (hasParam) {
						postData.Append("&");
					}

					postData.Append(name);
					postData.Append("=");

					string encodedValue = value;
					postData.Append(encodedValue);
					hasParam = true;
				}
			}
			return postData.ToString();
		}
	}
}
